/*
 * This file is part of Annuaire.
 *
 * Annuaire is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Annuaire is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Annuaire.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.miage.annuaire.bean;

import com.opensymphony.xwork2.ActionSupport;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.struts2.ServletActionContext;
import org.miage.annuaire.data.DataAccessFactory;
import org.miage.annuaire.data.XmlDataAccess;
import org.w3c.dom.Document;

/**
 * Ce bean contrôle la fonction de recherche dans l'annuaire.
 * @author altraver
 */
public class RechercheBean extends ActionSupport {

	/**
	 * Constructeur vide par défaut.
	 */
	public RechercheBean() {
		// Rien.
	}

	/**
	 * Exécute l'action de recherche dans l'annuaire.
	 */
	@Override
	public String execute() {

		// L'objet métier qui nous permet d'effectuer les recherches et
		// d'obtenir les résultats dans le format XML.
		XmlDataAccess xmlDataAccess = this.getXmlDataAccess();

		// Le document XML retourné par la recherche dans les objets métier.
		Document document = null;
		
		// Recherche:
		// TODO: !!! concaténer les résultats.
		try {
			document = xmlDataAccess.getMembres(this.nomRecherche,
					this.functionRecherche, this.structureRecherche);
		} catch (ParserConfigurationException e) {
			addActionError(e.getMessage());
			return ERROR;
		}

		String result = null;

		// Transformation du document XML en chaîne grâce aux règles XSL.
		try {
			result = this.transformDocumentToXmlString(document);
		} catch (TransformerException e) {
			addActionError(e.getMessage());
			return ERROR;
		}

		// Mise à jour de la propriété du bean.
		this.listeMembres = result;

		return SUCCESS;
	}

	/**
	 * Transforme un objet Document (une représentation XML en mémoire) en une
	 * chaîne de caractères selon les règles définies par des règles XSL.
	 * @param document Le document XML à transformer.
	 * @return Le résultat de la transformation.
	 * @throws TransformerException S'il y a eu une erreur dans la
	 * transformation du XML.
	 */
	protected String transformDocumentToXmlString(Document document)
			throws TransformerException {
		StringWriter chaineXML = new StringWriter();

		TransformerFactory factory = TransformerFactory.newInstance();
		Transformer transformer = null;

		try {
			transformer = factory.newTransformer(new StreamSource(
					new StringReader(this.getMembresXslContent())));
		} catch (IOException e) {
			throw new TransformerException(e);
		}

		transformer.setOutputProperty("encoding", "UTF-8");

		transformer.transform(new DOMSource(document), new StreamResult(
				chaineXML));

		return chaineXML.toString();
	}

	/**
	 * Récupère le contenu du fichier "xsl" sous forme d'une grosse chaîne de
	 * caractères.
	 * @return Le contenur du fichier "xsl".
	 * @throws IOException S'il y a une erreur dans la lecture du fichier.
	 */
	protected String getMembresXslContent() throws IOException {
		String xslContent = "";

		InputStream in = null;
		in = ServletActionContext.getServletContext().getResourceAsStream(
				"/resources/xml/recherche.xsl");
		BufferedReader br = new BufferedReader(new InputStreamReader(in));

		String line = null;
		while ((line = br.readLine()) != null) {
			xslContent = xslContent + line;
		}

		return xslContent;
	}

	/**
	 * Récupère une instance de l'objet 'xmlDataAccess'.
	 * @return Une instance de l'objet 'xmlDataAccess'.
	 */
	protected XmlDataAccess getXmlDataAccess() {
		return DataAccessFactory.getInstance().getXmlDataAccess();
	}

	/**
	 * Accesseur en lecture sur l'attribut 'nomRecherche'.
	 * @return Le nom recherché dans la recherche par nom.
	 */
	public String getNomRecherche() {
		return this.nomRecherche;
	}

	/**
	 * Accesseur en écriture sur l'attribut 'nomRecherche'.
	 * @param nomRecherche Le nom recherché dans la recherche par nom.
	 */
	public void setNomRecherche(String nomRecherche) {
		if (nomRecherche == null || nomRecherche.trim().isEmpty()) {
			this.nomRecherche = "";
		} else {
			this.nomRecherche = nomRecherche;
		}
	}

	/**
	 * Accesseur en lecture sur l'attribut 'functionRecherche'.
	 * @return La fonction recherchée dans la recherche par fonction.
	 */
	public String getFunctionRecherche() {
		return this.functionRecherche;
	}

	/**
	 * Accesseur en écriture sur l'attribut 'functionRecherche'.
	 * @param functionRecherche La fonction recherchée dans la recherche par
	 * fonction.
	 */
	public void setFunctionRecherche(String functionRecherche) {
		if (functionRecherche == null || functionRecherche.trim().isEmpty()) {
			this.functionRecherche = "";
		} else {
			this.functionRecherche = functionRecherche;
		}
	}

	/**
	 * Accesseur en lecture sur l'attribut 'structureRecherche'.
	 * @return La structure recherchée dans la recherche par structure.
	 */
	public String getStructureRecherche() {
		return this.structureRecherche;
	}

	/**
	 * Accesseur en écriture sur l'attribut 'structureRecherche'.
	 * @param structureRecherche La structure recherchée dans la recherche par
	 * structure.
	 */
	public void setStructureRecherche(String structureRecherche) {
		if (structureRecherche == null || structureRecherche.trim().isEmpty()) {
			this.structureRecherche = "";
		} else {
			this.structureRecherche = structureRecherche;
		}
	}

	/**
	 * Accesseur en lecture sur l'attribut 'listeMembres'.
	 * @return La liste des membres au format chaîne après transformation XSL.
	 */
	public String getListeMembres() {
		return this.listeMembres;
	}

	/**
	 * Le nom recherché dans la recherche par nom.
	 */
	private String nomRecherche = "";

	/**
	 * La fonction recherchée dans la recherche par fonction.
	 */
	private String functionRecherche = "";

	/**
	 * La structure recherchée dans la recherche par structure.
	 */
	private String structureRecherche = "";

	/**
	 * La liste des membres au format chaîne après transformation XSL.
	 */
	private String listeMembres;

	/**
	 * L'identifiant de sérialisation.
	 */
	private static final long serialVersionUID = 1L;
}
